﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using DevExpress.XtraEditors;
using DevExpress.XtraLayout;
using DevExpress.XtraLayout.Utils;
using WinUtilities.Class;
using WinUtilities.Form;
using WinUtilities.Properties;
using ComboBox = System.Windows.Forms.ComboBox;

namespace WinUtilities
{
    public enum CommandStatus
    {
        Inserted,
        Updated,
        Deleted,
        Canceled
    }

    public enum SearchMethods
    {
        StartWith,
        Contains
    }

    //Event For Find Button
    public delegate IBindingListView FindMethod();
    //Event For Cancel Button
    public delegate CommandStatus CancelMethod(object sender, EventArgs e);
    //Event For Save Button
    public delegate CommandStatus SaveMethod(object sender, EventArgs e);
    //Event For Delete Button
    public delegate CommandStatus DeleteMethod(object sender, EventArgs e);

    [Serializable]
    [Designer("System.Windows.Forms.Design.ParentControlDesigner,System.Design", typeof(IDesigner))]
    public partial class ItemControls : XtraUserControl
    {
        #region Properties & Event

        private Collection<SearchItem> _displayItems = new Collection<SearchItem>();
        private BindingList<SearchItem> _searchItems = new BindingList<SearchItem>();
        public string WhereExpression
        {
            get
            {
                string whereExpression = "";
                foreach (LayoutControlItem item in Layout_TextBox.Root.Items)
                    if (!String.IsNullOrEmpty(item.Control.Text))
                    {
                        string like = " LIKE '";
                        if (SearchMethod == SearchMethods.Contains)
                            like += "%";
                        whereExpression += item.Control.Name.Substring(4) + like + item.Control.Text.Replace("'", "''") + "%' AND ";
                    }
                if (whereExpression.Length > 0)
                    whereExpression = whereExpression.Remove(whereExpression.Length - 4);
                return whereExpression;
            }
        }

        [TypeConverter]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Description("Items to search for")]
        public BindingList<SearchItem> SearchItems
        {
            get { return _searchItems; }
            set { _searchItems = value; }
        }

        [Description("Search Methods")]
        [DefaultValue("Contains")]
        public SearchMethods SearchMethod
        {
            get;
            set;
        }

        [TypeConverter]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Description("Items to display results")]
        public Collection<SearchItem> DisplayItems
        {
            get { return _displayItems; }
            set { _displayItems = value; }
        }

        [Category("ButtonEvent")]
        public event FindMethod ButtonFindClick;

        [Category("ButtonEvent")]
        public event EventHandler ButtonNewClick;

        [Category("ButtonEvent")]
        public event EventHandler ButtonEditClick;

        [Category("ButtonEvent")]
        public event EventHandler ButtonPrintClick;

        [Category("ButtonEvent")]
        public event EventHandler ButtonRefreshClick;

        [Category("ButtonEvent")]
        public event EventHandler ButtonCloseClick;

        [Category("ButtonEvent")]
        public event SaveMethod ButtonSaveClick;

        [Category("ButtonEvent")]
        public event DeleteMethod ButtonDeleteClick;

        [Category("ButtonEvent")]
        public event CancelMethod ButtonCancelClick;

        [Category("ButtonEvent")]
        public event EventHandler ButtonHelpClick;

        [Category("FillData")]
        [Description("Method To Fill Log Result To Form")]
        public event FormShowLog.ShowLog DisplayLogResult;

        [Category("FillData")]
        [Description("Method To Fill Search Result To Form")]
        public event FormSearchResult.FillData DisplaySearchResult;

        [Category]

        #endregion

        #region Constructor

        public ItemControls()
        {
            InitializeComponent();
            var defaultSize = new Size(80, 42);

            //Fix Size For Button Layout
            Layout_F1.SizeConstraintsType = SizeConstraintsType.Custom;
            Layout_F1.MaxSize = defaultSize;
            Layout_F1.MinSize = defaultSize;
            Layout_F3.SizeConstraintsType = SizeConstraintsType.Custom;
            Layout_F3.MaxSize = defaultSize;
            Layout_F3.MinSize = defaultSize;
            Layout_F2.SizeConstraintsType = SizeConstraintsType.Custom;
            Layout_F2.MaxSize = defaultSize;
            Layout_F2.MinSize = defaultSize;
            Layout_F4.SizeConstraintsType = SizeConstraintsType.Custom;
            Layout_F4.MaxSize = defaultSize;
            Layout_F4.MinSize = defaultSize;
            Layout_F5.SizeConstraintsType = SizeConstraintsType.Custom;
            Layout_F5.MaxSize = defaultSize;
            Layout_F5.MinSize = defaultSize;
            Layout_F6.SizeConstraintsType = SizeConstraintsType.Custom;
            Layout_F6.MaxSize = defaultSize;
            Layout_F6.MinSize = defaultSize;
            Layout_F7.SizeConstraintsType = SizeConstraintsType.Custom;
            Layout_F7.MaxSize = defaultSize;
            Layout_F7.MinSize = defaultSize;
            Layout_F8.SizeConstraintsType = SizeConstraintsType.Custom;
            Layout_F8.MaxSize = defaultSize;
            Layout_F8.MinSize = defaultSize;
            Layout_F9.SizeConstraintsType = SizeConstraintsType.Custom;
            Layout_F9.MaxSize = defaultSize;
            Layout_F9.MinSize = defaultSize;
            Layout_F10.SizeConstraintsType = SizeConstraintsType.Custom;
            Layout_F10.MaxSize = defaultSize;
            Layout_F10.MinSize = defaultSize;
            Layout_F11.SizeConstraintsType = SizeConstraintsType.Custom;
            Layout_F11.MaxSize = defaultSize;
            Layout_F11.MinSize = defaultSize;
            // Event for creating search textbox base on SearchItems
            _searchItems.ListChanged += _searchItems_ListChanged;

            // Event for buttons
            btn_Find.Click += btn_Find_Click;
            btn_New.Click += btn_New_Click;
            btn_Edit.Click += btn_Edit_Click;
            btn_Delete.Click += btn_Delete_Click;
            btn_Print.Click += btn_Print_Click;
            btn_Refresh.Click += btn_Refresh_Click;
            btn_Close.Click += btn_Close_Click;
            btn_Cancel.Click += btn_Cancel_Click;
            btn_Help.Click += btn_Help_Click;
            btn_Save.Click += btn_Save_Click;
            btn_Log.Click += btn_Log_Click;
            ResetButtonStatus(false);
        }

        #endregion

        #region Private Method

        private void btn_Save_Click(object sender, EventArgs e)
        {
            CommandStatus commandState = ButtonSaveClick(this, e);
            if (commandState != CommandStatus.Canceled)
            {
                //GlobalUtilities.ControlEnable(false, btn_New, btn_Edit, btn_Refresh, btn_Delete);
                GlobalUtilities.ControlEnable(true, btn_New, btn_Edit, btn_Refresh, btn_Delete);
                if (ButtonSaveClick != null)
                {
                    //if (commandState == CommandState.Insert)
                    //{
                    //    //Command for Insert
                    //}
                    //else
                    //{
                    //Command for Update
                    ResetButtonStatus(true);
                    //}
                }
            }
        }

        private void ResetButtonStatus(bool AllowEdit)
        {
            GlobalUtilities.ControlEnable(false, btn_Print, btn_Help, btn_Print, btn_Cancel, btn_Save, btn_Log);
            GlobalUtilities.ControlEnable(true, btn_New, btn_Find, btn_Refresh, btn_Close);
            btn_Edit.Enabled = btn_Delete.Enabled = btn_Log.Enabled = AllowEdit;
            Focus();
        }

        private void btn_Help_Click(object sender, EventArgs e)
        {
            if (ButtonHelpClick != null)
                ButtonHelpClick(this, e);
        }


        private void btn_Log_Click(object sender, EventArgs e)
        {
            if (DisplayLogResult != null)
            {
                var formShowLog = new FormShowLog();
                DataSet dsLogResults = DisplayLogResult();
                formShowLog.DisplayLogResult(dsLogResults);
                formShowLog.ShowDialog();
            }
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            if (ButtonCancelClick != null)
            {
                CommandStatus commandState = ButtonCancelClick(this, e);
                if (commandState != CommandStatus.Canceled)
                    if (commandState == CommandStatus.Inserted)
                        ResetButtonStatus(false);
                    else if (commandState == CommandStatus.Updated)
                        ResetButtonStatus(true);
            }
        }

        private void btn_Refresh_Click(object sender, EventArgs e)
        {
            if (ButtonRefreshClick != null)
                ButtonRefreshClick(this, e);
        }

        private void btn_Close_Click(object sender, EventArgs e)
        {
            if (ButtonCloseClick != null)
                ButtonCloseClick(this, e);
        }

        private void btn_Print_Click(object sender, EventArgs e)
        {
            if (ButtonPrintClick != null)
                ButtonPrintClick(this, e);
        }

        private void btn_Delete_Click(object sender, EventArgs e)
        {
            if (ButtonDeleteClick != null)
            {
                CommandStatus commandStatus = ButtonDeleteClick(this, e);
                if (commandStatus == CommandStatus.Deleted)
                {
                    ResetButtonStatus(false);
                }
            }
        }

        private void btn_Edit_Click(object sender, EventArgs e)
        {
            GlobalUtilities.ControlEnable(false, btn_New, btn_Edit, btn_Delete, btn_Find, btn_Print, btn_Refresh,
                                          btn_Close,btn_Log);
            GlobalUtilities.ControlEnable(true, btn_Save, btn_Cancel);
            if (ButtonEditClick != null)
                ButtonEditClick(this, e);
        }

        private void btn_New_Click(object sender, EventArgs e)
        {
            GlobalUtilities.ControlEnable(false, btn_New, btn_Edit, btn_Delete, btn_Find, btn_Print, btn_Refresh,
                                          btn_Close,btn_Log);
            GlobalUtilities.ControlEnable(true, btn_Save, btn_Cancel);
            if (ButtonNewClick != null)
                ButtonNewClick(this, e);
        }

        private void btn_Find_Click(object sender, EventArgs e)
        {
            if (ButtonFindClick != null)
            {
                IBindingListView searchResults = ButtonFindClick();
                if (searchResults.Count > 0)
                {
                    if (searchResults.Count == 1)
                    {
                        DisplaySearchResult(searchResults[0]);
                        GlobalUtilities.ControlEnable(true, btn_Edit, btn_Delete, btn_Log);
                    }
                    else
                    {
                        var formSearchResult = new FormSearchResult { DisplayItems = DisplayItems };
                        formSearchResult.FillSearchResult(searchResults);
                        formSearchResult.DisplaySearchResult += DisplaySearchResult;
                        formSearchResult.ShowDialog();
                        if (formSearchResult.HaveResult)
                            GlobalUtilities.ControlEnable(true, btn_Edit, btn_Delete, btn_Log);
                    }
                }
                else
                    MessageBox.Show(Resources.SearchNotFound);
            }
        }


        private void _searchItems_ListChanged(object sender, ListChangedEventArgs e)
        {
            InitializeSearchPanel();
            CopyToDisplayResultList();
        }

        private void CopyToDisplayResultList()
        {
            foreach (SearchItem searchItem in _searchItems)
            {
                if (!_displayItems.Contains(searchItem))
                    _displayItems.Add(searchItem);
            }
        }

        private void InitializeSearchPanel()
        {
            Layout_TextBox.Root.Clear();
            //Create Layout For Items
            LayoutControlItem pastItem = null;
            for (int i = 0; i < SearchItems.Count - 1; i++)
            {
                SearchItem searchItem = SearchItems[i];
                Control control;
                switch (searchItem.FieldType)
                {
                    case SearchItem.EnumFieldType.Text:
                        control = new TextBox();
                        break;
                    case SearchItem.EnumFieldType.Combo:
                        control = new ComboBox();
                        break;
                    default:
                        control = new TextBox();
                        break;
                }

                control.Name = "txtF" + searchItem.FieldName;

                control.KeyDown += control_KeyDown;
                var item = new LayoutControlItem(Layout_TextBox, control)
                               {
                                   Name = "itemF" + searchItem.FieldName,
                                   Control = control,
                                   Text = searchItem.Name
                               };
                var defaultSize = new Size(200, 24);
                if (searchItem.FieldLength > 0)
                    defaultSize.Width = (item.Text.Length + searchItem.FieldLength) * 10;
                item.MinSize = defaultSize;
                item.MaxSize = defaultSize;
                item.SizeConstraintsType = SizeConstraintsType.Custom;
                if (pastItem == null)
                    Layout_TextBox.Root.Add(item);
                else
                    item.Move(pastItem, InsertType.Right);
                pastItem = item;
            }
            //Create Layout For Last Item

            if (SearchItems.Count > 0)
            {
                SearchItem lastItem = SearchItems[SearchItems.Count - 1];
                Control control;
                switch (lastItem.FieldType)
                {
                    case SearchItem.EnumFieldType.Text:
                        control = new TextBox();
                        break;
                    case SearchItem.EnumFieldType.Combo:
                        control = new ComboBox();
                        break;
                    default:
                        control = new TextBox();
                        break;
                }
                control.Name = "txtF" + lastItem.FieldName;
                control.KeyDown += lastcontrol_KeyDown;
                var item = new LayoutControlItem(Layout_TextBox, control) { Name = "itemF" + lastItem.FieldName, Control = control, Text = lastItem.Name + " :" };
                if (pastItem == null)
                    Layout_TextBox.Root.Add(item);
                else
                    item.Move(pastItem, InsertType.Right);
            }
        }

        private void lastcontrol_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
                btn_Find_Click(null, null);
        }

        private void control_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
                SendKeys.Send("{TAB}");
        }

        #endregion

        #region Key Preview

        //----------------------------------------------
        // Define the PeekMessage API call
        //----------------------------------------------

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern bool PeekMessage([In, Out] ref MSG msg,
                                               HandleRef hwnd, int msgMin, int msgMax, int remove);

        //----------------------------------------------

        /// <summary> 
        /// Trap any keypress before child controls get hold of them
        /// </summary>
        /// <param name="m">Windows message</param>
        /// <returns>True if the keypress is handled</returns>
        protected override bool ProcessKeyPreview(ref Message m)
        {
            const int WM_KEYDOWN = 0x100;
            const int WM_KEYUP = 0x101;
            const int WM_CHAR = 0x102;
            const int WM_SYSCHAR = 0x106;
            const int WM_SYSKEYDOWN = 0x104;
            const int WM_SYSKEYUP = 0x105;
            const int WM_IME_CHAR = 0x286;

            if ((m.Msg != WM_CHAR) && (m.Msg != WM_SYSCHAR) && (m.Msg != WM_IME_CHAR))
            {
                KeyEventArgs e = new KeyEventArgs(((Keys)((int)((long)m.WParam))) | ModifierKeys);
                if ((m.Msg == WM_KEYDOWN) || (m.Msg == WM_SYSKEYDOWN))
                {
                    e.Handled = TrappedKeyDown(e.KeyData);
                }
                //else
                //{
                //    TrappedKeyUp(e);
                //}

                // Remove any WM_CHAR type messages if supresskeypress is true.
                if (e.SuppressKeyPress)
                {
                    RemovePendingMessages(WM_CHAR, WM_CHAR);
                    RemovePendingMessages(WM_SYSCHAR, WM_SYSCHAR);
                    RemovePendingMessages(WM_IME_CHAR, WM_IME_CHAR);
                }

                if (e.Handled)
                {
                    return e.Handled;
                }
            }
            return base.ProcessKeyPreview(ref m);
        }

        private void RemovePendingMessages(int msgMin, int msgMax)
        {
            if (!IsDisposed)
            {
                var msg = new MSG();
                IntPtr handle = Handle;
                while (PeekMessage(ref msg,
                                   new HandleRef(this, handle), msgMin, msgMax, 1))
                {
                }
            }
        }

        /// <summary>
        /// This routine gets called if a keydown has been trapped 
        /// before a child control can get it.
        /// </summary>
        /// <param name="keyData"></param>
        public bool TrappedKeyDown(Keys keyData)
        {
            if (keyData == Keys.F1)
            {
                if (btn_New.Enabled) btn_New_Click(btn_New, null);
                return true;
            }
            if (keyData == Keys.F2)
            {
                if (btn_Edit.Enabled) btn_Edit_Click(btn_Edit, null);
                return true;
            }
            if (keyData == Keys.F3)
            {
                if (btn_Delete.Enabled) btn_Delete_Click(btn_Delete, null);
                return true;
            }
            if (keyData == Keys.F4)
            {
                if (btn_Find.Enabled) btn_Find_Click(btn_Find, null);
                return true;
            }
            if (keyData == Keys.F5)
            {
                if (btn_Print.Enabled) btn_Print_Click(btn_Find, null);
                return true;
            }
            if (keyData == Keys.F6)
            {
                if (btn_Refresh.Enabled) btn_Refresh_Click(btn_Refresh, null);
                return true;
            }
            if (keyData == Keys.F7)
            {
                if (btn_Close.Enabled) btn_Close_Click(btn_Close, null);
                return true;
            }
            if (keyData == Keys.F8)
            {
                if (btn_Save.Enabled) btn_Save_Click(btn_Save, null);
                return true;
            }
            if (keyData == Keys.F9)
            {
                if (btn_Cancel.Enabled) btn_Cancel_Click(btn_Cancel, null);
                return true;
            }
            if (keyData == Keys.F10)
            {
                if (btn_Help.Enabled) btn_Help_Click(btn_Help, null);
                return true;
            }
            if (keyData == Keys.F11)
            {
                if (btn_Log.Enabled) btn_Log_Click(btn_Log, null);
                return true;
            }
            return false;
        }

        #region Nested type: MSG

        private struct MSG
        {
            public IntPtr hwnd;
            public IntPtr lParam;
            public int message;
            public int pt_x;
            public int pt_y;
            public int time;
            public IntPtr wParam;
        }

        #endregion

        #endregion
    }
}